package gorm

import (
	"os"
	"path/filepath"
	"strings"

	Log "github.com/cihub/seelog"
	"gopkg.in/ini.v1"

	//"gorm.io/driver/sqlite"//这个驱动需要使用CGO
	"github.com/glebarez/sqlite" //这个驱动不需要使用CGO
	"gorm.io/driver/mysql"
	gg "gorm.io/gorm"
	"gorm.io/gorm/logger"
)

type GormDB = *gg.DB

var (
	globGormDB  *gg.DB            //数据库操作对象
	dbVariables map[string]string //数据库名称映射集合
)

// 初始化
func init() {
	//SetupLogger()

	root := ""
	exePath, err := os.Executable()
	if err != nil {
		root = "."
	}

	root, _ = filepath.EvalSymlinks(filepath.Dir(exePath))

	configFilePath := strings.Replace(root+"/config/app.ini", "\\", "/", -1)

	_, err = os.Stat(configFilePath) //os.Stat获取文件信息
	if err != nil {
		if !os.IsExist(err) {
			Log.Error("配置文件不存在:", err)
			os.Exit(1)
			return
		}
	}

	cfg, err := ini.Load(configFilePath)
	if err != nil {
		Log.Error("配置文件读取错误:", err)
		os.Exit(1)
	}

	if !cfg.HasSection("DataSource") {
		Log.Debug("配置文件没有DataSource,不进行数据库连接")
		return
	}

	dbVariables = make(map[string]string)

	DbVariables := cfg.Section("DbVariables")
	for i := 0; i < len(DbVariables.Keys()); i++ {
		key := DbVariables.Keys()[i].Name()
		value, _ := DbVariables.GetKey(key)
		if value != nil {
			dbVariables[key] = value.String()
		}
	}

	DataSource := cfg.Section("DataSource")

	user := "root"
	value, _ := DataSource.GetKey("User")
	if value != nil {
		user = value.String()
	}

	pass := "view"
	value, _ = DataSource.GetKey("Pass")
	if value != nil {
		pass = value.String()
	}

	if (strings.HasPrefix(pass, "${")) && (strings.HasSuffix(pass, "}")) {
		pass = AesUtil{}.Decrypt(pass[2:len(pass)-1], "bricks")
	}

	dbType := "mysql"
	value, _ = DataSource.GetKey("Type")
	if value != nil {
		dbType = strings.ToLower(value.String())
	}

	ip := "127.0.0.1"
	value, _ = DataSource.GetKey("Ip")
	if value != nil {
		ip = value.String()
	}

	port := "3306"
	value, _ = DataSource.GetKey("Port")
	if value != nil {
		port = value.String()
	}

	dbName := "mysql" //如果是sqlite则是数据库文件路径和名称
	value, _ = DataSource.GetKey("MainDb")
	if value != nil {
		dbName = value.String()
	}

	PrintSql := false
	value, _ = DataSource.GetKey("PrintSql")
	if value != nil {
		tmp, _ := value.Int()
		PrintSql = tmp == 1
	}

	AutoMigrate := false //是否开启AutoMigrate功能(会创建表、缺失的外键、约束、列和索引)
	value, _ = DataSource.GetKey("AutoMigrate")
	if value != nil {
		tmp, _ := value.Int()
		AutoMigrate = tmp == 1
	}

	dbConfig := &gg.Config{
		DisableForeignKeyConstraintWhenMigrating: !AutoMigrate,
	}

	if PrintSql {
		dbConfig.Logger = logger.Default.LogMode(logger.Info) //开启sql打印
	}

	if dbType == "mysql" {
		//dsn := "root:view@tcp(127.0.0.1:3306)/Dev_BricksBaseSystem?charset=utf8mb4&parseTime=True&loc=Local"
		//dsn := user + ":" + pass + "@tcp(" + ip + ":" + port + ")/" + dbName + "?charset=utf8mb4&serverTimezone=GMT%2B8&parseTime=True&loc=Local"
		dsn := user + ":" + pass + "@tcp(" + ip + ":" + port + ")/" + dbName + "?charset=utf8mb4&parseTime=True&loc=Local"
		//dsn := user + ":" + pass + "@tcp(" + ip + ":" + port + ")/" + dbName + "?charset=utf8mb4&loc=Local"
		globGormDB, err = gg.Open(mysql.Open(dsn), dbConfig)
	} else if dbType == "sqlite" {
		if strings.HasPrefix(dbName, "./") {
			dbName = strings.Replace(dbName, "./", root+"/", 1)
			dbName = strings.Replace(dbName, "\\", "/", -1)
			dbName = strings.Replace(dbName, "//", "/", -1)
		}

		createFileDir(dbName)
		globGormDB, err = gg.Open(sqlite.Open(dbName), dbConfig)
	}

	if err != nil {
		Log.Error("连接数据库错误:", err)
		return
	}
}

// 取gorm操作对象
func GetDB() GormDB {
	return globGormDB
}

/**
 * 创建文件所在文件夹
 * 注意:必须是文件,否则只能创建出上级路径
 * @param filePath 文件路径
 * @return bool:是否成功(如果路径已经存在则不会创建,但返回true); error:错误信息
 */
func createFileDir(filePath string) (bool, error) {
	path := filepath.Dir(filePath) //获取上级目录
	_, err := os.Stat(path)        //os.Stat获取文件信息
	if err == nil {                //获取成功,说明文件存在
		return true, nil
	}

	if os.IsExist(err) { //再次判断路径是否存在,也可以使用os.IsNotExist(err)来判断是否不存在
		return true, nil
	}

	err = os.MkdirAll(path, os.ModePerm)
	if err != nil {
		return false, err
	}

	return true, nil
}
